package com.hipac.hq;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiCodeBlock;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiModifierList;
import com.intellij.psi.PsiType;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.impl.source.PsiJavaFileImpl;
import com.intellij.psi.impl.source.javadoc.PsiDocTokenImpl;

import java.util.UUID;

/**
 * 将java Bean属于转成 json，并带上注释，主要是为了解决给前端提供数据结构的问题
 *
 * @author huqiang
 * @since 2018/11/8 4:29 PM
 */
public class Bean2Json extends AnAction {
    private static final Logger LOG = Logger.getInstance(Bean2Json.class);

    @Override
    public void actionPerformed(AnActionEvent anActionEvent) {
        PsiElement psiElement = getPsiElement(anActionEvent);
        bean2JsonMethod(psiElement);
    }


    /**
     * 启动写线程
     *
     * @param psiElement
     */
    private void bean2JsonMethod(final PsiElement psiElement) {
        new WriteCommandAction.Simple(psiElement.getProject(), psiElement.getContainingFile()) {
            @Override
            protected void run() throws Throwable {
                buildJson(psiElement);
            }
        }.execute();
    }

    private void buildJson(PsiElement psiElement) {
        PsiJavaFileImpl javaFile = null;
        if (psiElement instanceof PsiJavaFileImpl) {
            javaFile = (PsiJavaFileImpl) psiElement;
        }
        if (javaFile == null) {
            return;
        }
        PsiField[] fields = javaFile.getClasses()[0].getFields();
        if (fields == null) {
            return;
        }
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        for (PsiField field : fields) {
            PsiModifierList modifierList = field.getModifierList();
            if (modifierList == null || modifierList.hasModifierProperty(PsiModifier.STATIC) || modifierList.hasModifierProperty(PsiModifier.FINAL) || modifierList.hasModifierProperty(PsiModifier.SYNCHRONIZED)) {
                LOG.info("skip static final field  ," + field.getName());
                continue;
            }

            PsiType type = field.getType();
            sb.append("\n");
            sb.append("\"").append(field.getName()).append("\"").append(": ");
            if (type instanceof PsiClassReferenceType) {
                String referenceName = ((PsiClassReferenceType) type).getReference().getReferenceName();
                if (referenceName.equals("Integer") || referenceName.equals("Long")) {
                    sb.append("2");
                } else if (referenceName.equals("String")) {
                    sb.append("\"");
                    sb.append(UUID.randomUUID().toString().replaceAll("-", ""));
                    sb.append("\"");
                } else if (referenceName.equals("Boolean")) {
                    sb.append("true");
                } else if (referenceName.equals("Date")) {
                    sb.append("\"2019-01-01\"");
                } else if (referenceName.equals("Double")) {
                    sb.append("2.0");
                } else {
                    sb.append("\"\"");
                }
            } else if (type instanceof PsiType) {
                LOG.info(field.getName() + "  " + type);
                if (type.equalsToText(PsiType.LONG.getName())) {
                    sb.append("2");
                } else if (type.equals(PsiType.INT)) {
                    sb.append("1");
                } else if (type.equals(PsiType.BOOLEAN)) {
                    sb.append("true");
                }
            }
            sb.append(",");
            sb.append("//").append(format(field));
        }
        String s = sb.append("\n").append("}").toString();
        int idx = s.lastIndexOf(",");
        s = s.substring(0, idx) + s.substring(idx + 1);
        PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(psiElement.getProject());
        PsiCodeBlock codeBlock = elementFactory.createCodeBlockFromText(s, psiElement);
        javaFile.add(codeBlock);
    }


    private String format(PsiField field) {
        String oldContent = "";
        if (field.getDocComment() == null) {
            //  //单行注释 \n private String a;
            if (field.getText().lastIndexOf("\n") == -1) {
                return "";
            }
            oldContent = field.getText().substring(0, field.getText().lastIndexOf("\n") + 1).replace("//", "").replaceAll("\n", "");
        } else {
            PsiElement[] descriptionElements = field.getDocComment().getDescriptionElements();

            for (PsiElement descriptionElement : descriptionElements) {
                if (descriptionElement instanceof PsiDocTokenImpl) {
                    oldContent = oldContent + " " + ((PsiDocTokenImpl) descriptionElement).getText().replaceAll("\n", " ");
                }
            }
        }
        LOG.info("fieldName: " + field.getName() + ", doc: " + oldContent);
        return oldContent;
    }

    private PsiElement getPsiElement(AnActionEvent e) {
        PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
        Editor editor = e.getData(PlatformDataKeys.EDITOR);
        if (psiFile == null || editor == null || !(psiFile instanceof PsiJavaFileImpl)) {
            e.getPresentation().setEnabled(false);
            return null;
        }

        return psiFile.getNavigationElement();
    }
}
